package com.ruoyi.weixin.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaUserService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.weixin.config.WxMaConfiguration;
import com.ruoyi.weixin.constant.ConfigConstant;
import com.ruoyi.weixin.constant.WxMaConstants;
import com.ruoyi.weixin.domain.WxUser;
import com.ruoyi.weixin.domain.vo.MpPhoneNumber;
import com.ruoyi.weixin.domain.vo.ThirdSession;
import com.ruoyi.weixin.domain.vo.WxOpenDataDTO;
import com.ruoyi.weixin.mapper.WxUserMapper;
import com.ruoyi.weixin.service.WxUserService;
import com.ruoyi.weixin.utils.ThirdSessionHolder;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@AllArgsConstructor
public class WxUserServiceImpl extends ServiceImpl<WxUserMapper, WxUser> implements WxUserService {

    private final RedisTemplate redisTemplate;
    /**
     * 小程序登录
     * @param appId
     * @param jsCode
     * @return
     */
    @Override
    public WxUser loginMa(String appId, String jsCode) throws WxErrorException {
        WxMaJscode2SessionResult jscode2session = WxMaConfiguration.getMaService(appId).jsCode2SessionInfo(jsCode);
        WxUser wxUser = this.getByOpenId(jscode2session.getOpenid());
        if(wxUser==null) {
            //新增微信用户
            wxUser = new WxUser();
            wxUser.setAppType(ConfigConstant.WX_APP_TYPE_1);
            wxUser.setOpenId(jscode2session.getOpenid());
            wxUser.setSessionKey(jscode2session.getSessionKey());
            wxUser.setUnionId(jscode2session.getUnionid());
            try{
                this.save(wxUser);
            }catch (DuplicateKeyException e){
                if(e.getMessage().contains("uk_appid_openid")){
                    wxUser = this.getByOpenId(wxUser.getOpenId());
                }
            }
        } else {
            //更新SessionKey
            wxUser.setAppType(ConfigConstant.WX_APP_TYPE_1);
            wxUser.setOpenId(jscode2session.getOpenid());
            wxUser.setSessionKey(jscode2session.getSessionKey());
            wxUser.setUnionId(jscode2session.getUnionid());
            this.updateById(wxUser);
        }

        String thirdSessionKey = UUID.randomUUID().toString();
        ThirdSession thirdSession = new ThirdSession();
        thirdSession.setAppId(appId);
        thirdSession.setSessionKey(wxUser.getSessionKey());
        thirdSession.setWxUserId(wxUser.getId());
        thirdSession.setOpenId(wxUser.getOpenId());
        //将3rd_session和用户信息存入redis，并设置过期时间
        String key = WxMaConstants.THIRD_SESSION_BEGIN + ":" + thirdSessionKey;

        redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(thirdSession) , WxMaConstants.TIME_OUT_SESSION, TimeUnit.HOURS);
        wxUser.setSessionKey(thirdSessionKey);
        return wxUser;
    }

    @Override
    public String getPhoneNum(String appId, MpPhoneNumber mpPhoneNumber) {
        WxMaUserService wxMaUserService = WxMaConfiguration.getMaService(appId).getUserService();

        String sessionKey = ThirdSessionHolder.getThirdSession().getSessionKey();
        WxMaPhoneNumberInfo phoneNumberInfo = wxMaUserService.getPhoneNoInfo(sessionKey, mpPhoneNumber.getEncryptedData(), mpPhoneNumber.getIv());
        return phoneNumberInfo.getPhoneNumber();
    }

    /**
     * 根据openId获取用户
     * @param openId
     * @return
     */
    @Override
    public WxUser getByOpenId(String openId){
        return this.baseMapper.selectOne(Wrappers.<WxUser>lambdaQuery()
                .eq(WxUser::getOpenId,openId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WxUser saveOrUptateWxUser(WxOpenDataDTO wxOpenDataDTO) {
        WxMaUserService wxMaUserService = WxMaConfiguration.getMaService(wxOpenDataDTO.getAppId()).getUserService();
        WxMaUserInfo wxMaUserInfo = wxMaUserService.getUserInfo(wxOpenDataDTO.getSessionKey(), wxOpenDataDTO.getEncryptedData(), wxOpenDataDTO.getIv());
        WxUser wxUser = new WxUser();
        BeanUtil.copyProperties(wxMaUserInfo,wxUser);
        wxUser.setId(wxOpenDataDTO.getUserId());
        wxUser.setSex(wxMaUserInfo.getGender());
        wxUser.setHeadimgUrl(wxMaUserInfo.getAvatarUrl());
        baseMapper.updateById(wxUser);
        wxUser = baseMapper.selectById(wxUser.getId());
        return wxUser;
    }


}
